package com.zeyu.framework.tools.report.dynamic;

import com.zeyu.framework.utils.StringUtils;
import net.sf.dynamicreports.report.base.expression.AbstractValueFormatter;
import net.sf.dynamicreports.report.builder.HyperLinkBuilder;
import net.sf.dynamicreports.report.builder.ReportTemplateBuilder;
import net.sf.dynamicreports.report.builder.component.ComponentBuilder;
import net.sf.dynamicreports.report.builder.datatype.BigDecimalType;
import net.sf.dynamicreports.report.builder.style.StyleBuilder;
import net.sf.dynamicreports.report.builder.tableofcontents.TableOfContentsCustomizerBuilder;
import net.sf.dynamicreports.report.constant.HorizontalTextAlignment;
import net.sf.dynamicreports.report.constant.VerticalTextAlignment;
import net.sf.dynamicreports.report.definition.ReportParameters;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static net.sf.dynamicreports.report.builder.DynamicReports.cmp;
import static net.sf.dynamicreports.report.builder.DynamicReports.hyperLink;
import static net.sf.dynamicreports.report.builder.DynamicReports.stl;
import static net.sf.dynamicreports.report.builder.DynamicReports.tableOfContentsCustomizer;
import static net.sf.dynamicreports.report.builder.DynamicReports.template;

/**
 * 报表的模板信息
 * Created by zeyuphoenix on 16/9/4.
 */
public class Templates {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(Templates.class);

    public static StyleBuilder rootStyle;
    public static final StyleBuilder boldStyle;
    public static final StyleBuilder italicStyle;
    public static final StyleBuilder boldCenteredStyle;
    public static final StyleBuilder bold8CenteredStyle;
    public static final StyleBuilder bold10CenteredStyle;
    public static final StyleBuilder bold12CenteredStyle;
    public static final StyleBuilder bold14CenteredStyle;
    public static final StyleBuilder bold18CenteredStyle;
    public static final StyleBuilder bold22CenteredStyle;
    public static final StyleBuilder columnStyle;
    public static final StyleBuilder columnTitleStyle;
    public static final StyleBuilder groupStyle;
    public static final StyleBuilder subtotalStyle;

    public static final ReportTemplateBuilder reportTemplate;
    public static final CurrencyType currencyType;
    public static final ComponentBuilder<?, ?> dynamicReportsComponent;
    public static final ComponentBuilder<?, ?> footerComponent;

    /**
     * 如果系统不存在字体,程序中字体解压路径
     */
    public static final String FONT_DIR = System.getProperty("java.io.tmpdir")
            + File.separator + ".framework";

    static {
        // 注册字体,否则PDF会字体错误
        // Linux需要拷贝字体到工程.
        try {
            // String fontPath = extractedTTF();
            rootStyle = stl
                    .style()
                    .setPadding(2)
                    .setFontName("FreeUniversSimHei");
        } catch (Exception e) {
            logger.error("font loading error: ", e);
        }

        boldStyle = stl.style(rootStyle).bold();
        italicStyle = stl.style(rootStyle).italic();
        boldCenteredStyle = stl.style(boldStyle).setTextAlignment(
                HorizontalTextAlignment.CENTER, VerticalTextAlignment.MIDDLE);
        bold8CenteredStyle = stl.style(boldCenteredStyle).setFontSize(8);
        bold10CenteredStyle = stl.style(boldCenteredStyle).setFontSize(10);
        bold12CenteredStyle = stl.style(boldCenteredStyle).setFontSize(12);
        bold14CenteredStyle = stl.style(boldCenteredStyle).setFontSize(14);
        bold18CenteredStyle = stl.style(boldCenteredStyle).setFontSize(18);
        bold22CenteredStyle = stl.style(boldCenteredStyle).setFontSize(22);
        columnStyle = stl.style(rootStyle).setVerticalTextAlignment(
                VerticalTextAlignment.MIDDLE);
        columnTitleStyle = stl.style(columnStyle).setBorder(stl.pen1Point())
                .setHorizontalTextAlignment(HorizontalTextAlignment.CENTER)
                .setBackgroundColor(Color.LIGHT_GRAY).bold();
        groupStyle = stl.style(boldStyle).setHorizontalTextAlignment(
                HorizontalTextAlignment.LEFT);
        subtotalStyle = stl.style(boldStyle).setTopBorder(stl.pen1Point());

        StyleBuilder crosstabGroupStyle = stl.style(columnTitleStyle);
        StyleBuilder crosstabGroupTotalStyle = stl.style(columnTitleStyle)
                .setBackgroundColor(new Color(170, 170, 170));
        StyleBuilder crosstabGrandTotalStyle = stl.style(columnTitleStyle)
                .setBackgroundColor(new Color(140, 140, 140));
        StyleBuilder crosstabCellStyle = stl.style(columnStyle).setBorder(
                stl.pen1Point());

        TableOfContentsCustomizerBuilder tableOfContentsCustomizer = tableOfContentsCustomizer()
                .setHeadingStyle(0, stl.style(rootStyle).bold());

        reportTemplate = template().setLocale(Locale.CHINA)
                .setColumnStyle(columnStyle)
                .setColumnTitleStyle(columnTitleStyle)
                .setGroupStyle(groupStyle).setGroupTitleStyle(groupStyle)
                .setSubtotalStyle(subtotalStyle).highlightDetailEvenRows()
                .crosstabHighlightEvenRows()
                .setCrosstabGroupStyle(crosstabGroupStyle)
                .setCrosstabGroupTotalStyle(crosstabGroupTotalStyle)
                .setCrosstabGrandTotalStyle(crosstabGrandTotalStyle)
                .setCrosstabCellStyle(crosstabCellStyle)
                .setTableOfContentsCustomizer(tableOfContentsCustomizer);

        currencyType = new CurrencyType();

        HyperLinkBuilder link = hyperLink("FrameWork");
        dynamicReportsComponent = cmp.horizontalList(
                cmp.image(Templates.class.getResource("reports.png")).setFixedDimension(60, 60),
                cmp.verticalList(
                        cmp.text("zeyuphoenix的报表")
                                .setStyle(bold22CenteredStyle)
                                .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT),
                        cmp.text("www.zeyuphoenix.com").setStyle(italicStyle)
                                .setHyperLink(link))).setFixedWidth(300);

        footerComponent = cmp.pageXofY().setStyle(
                stl.style(boldCenteredStyle).setTopBorder(stl.pen1Point()));
    }

    // ================================================================
    // Fields
    // ================================================================

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * Creates custom component which is possible to add to any report band
     * component
     */
    public static ComponentBuilder<?, ?> createTitleComponent(String label) {
        return cmp
                .horizontalList()
                .add(dynamicReportsComponent,
                        cmp.text(label)
                                .setStyle(bold18CenteredStyle)
                                .setHorizontalTextAlignment(HorizontalTextAlignment.RIGHT))
                .newRow().add(cmp.line())
                .newRow().add(cmp.verticalGap(10));
    }

    public static CurrencyValueFormatter createCurrencyValueFormatter(
            String label) {
        return new CurrencyValueFormatter(label);
    }

    /**
     * 解压jar内字体到指定目录
     */
    private static String extractedTTF() throws UnsupportedEncodingException, URISyntaxException {

        // 获取当前class路径,判断属于jar还是class方式启动
        String pwd = Templates.class.getResource(Templates.class.getSimpleName() + ".class").getPath();
        logger.debug("now class path is {}", pwd);
        String file = FONT_DIR + File.separator + "simhei.ttf";
        if (pwd.contains(".jar!")) {
            // jar方式
            logger.info("load ttf with jar file");
            File tmpFile = new File(FONT_DIR);
            if (!tmpFile.exists()) {
                boolean mkdirs = tmpFile.mkdirs();
                if (mkdirs && tmpFile.exists()) {
                    // extracted ttf file
                    // 获取jar的路径
                    URL location = Templates.class.getProtectionDomain().getCodeSource().getLocation();
                    String jarPath = URLDecoder.decode(location.getPath(), "utf-8");
                    logger.debug("jar file path is {}", jarPath);

                    // windows系统可以mac系统下,前面多一个file: 后面多一个!/
                    jarPath = StringUtils.replace(jarPath, "file:", "");
                    jarPath = StringUtils.replace(jarPath, "!/", "");

                    JarFile jarFile = null;
                    try {
                        // find all ttf
                        jarFile = new JarFile(new File(jarPath));
                        Enumeration<JarEntry> entries = jarFile.entries();
                        String ttf = null;
                        while (entries.hasMoreElements()) {
                            JarEntry entry = entries.nextElement();
                            if (StringUtils.contains(entry.getName(), "simhei.ttf")) {
                                ttf = entry.getName();
                                break;
                            }
                        }

                        // copy ttf
                        if (StringUtils.isNoneBlank(ttf)) {
                            logger.debug("copy to classpath file is {}", ttf);
                            InputStream is = Templates.class.getResourceAsStream("simhei.ttf");
                            OutputStream os = new FileOutputStream(file);

                            IOUtils.copy(is, os);

                            is.close();
                            os.close();
                        }

                    } catch (Exception e) {
                        logger.error("open jar file error ", e);
                    } finally {
                        try {
                            if (jarFile != null)
                                jarFile.close();
                        } catch (IOException ignored) {
                        }
                    }
                }
            }
        } else {
            // class方式
            logger.info("load ttf with class file");
            file = Templates.class.getResource("simhei.ttf").getFile();
            logger.debug("ttf path is {}", file);
        }

        return file;
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    /**
     * 格式化方式
     */
    public static class CurrencyType extends BigDecimalType {

        // ================================================================
        // Constants
        // ================================================================
        /**
         * UID
         */
        private static final long serialVersionUID = 1L;

        // ================================================================
        // Methods from/for super Interfaces or SuperClass
        // ================================================================

        @Override
        public String getPattern() {
            return "$ #,###.00";
        }
    }


    /**
     * value 格式化
     */
    private static class CurrencyValueFormatter extends AbstractValueFormatter<String, Number> {

        // ================================================================
        // Constants
        // ================================================================
        /**
         * UID
         */
        private static final long serialVersionUID = 1L;

        // ================================================================
        // Fields
        // ================================================================

        private String label;

        // ================================================================
        // Constructors
        // ================================================================

        public CurrencyValueFormatter(String label) {
            this.label = label;
        }

        // ================================================================
        // Methods from/for super Interfaces or SuperClass
        // ================================================================

        @Override
        public String format(Number value, ReportParameters reportParameters) {
            return label + currencyType.valueToString(value, reportParameters.getLocale());
        }
    }

    // ================================================================
    // Test Methods
    // ================================================================

}
